home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / DB / fbsql.php < prev    next >
PHP Script  |  2004-10-01  |  19KB  |  656 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Frank M. Kromann <frank@frontbase.com>                       |
  17. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: fbsql.php,v 1.36 2004/06/24 15:24:56 danielc Exp $
  21.  
  22.  
  23. // XXX legend:
  24. //
  25. // XXX ERRORMSG: The error message from the fbsql function should
  26. //               be registered here.
  27. //
  28. // TODO/wishlist:
  29. // longReadlen
  30. // binmode
  31.  
  32.  
  33. require_once 'DB/common.php';
  34.  
  35. /**
  36.  * Database independent query interface definition for PHP's FrontBase
  37.  * extension.
  38.  *
  39.  * @package  DB
  40.  * @version  $Id: fbsql.php,v 1.36 2004/06/24 15:24:56 danielc Exp $
  41.  * @category Database
  42.  * @author   Frank M. Kromann <frank@frontbase.com>
  43.  */
  44. class DB_fbsql extends DB_common
  45. {
  46.     // {{{ properties
  47.  
  48.     var $connection;
  49.     var $phptype, $dbsyntax;
  50.     var $prepare_tokens = array();
  51.     var $prepare_types = array();
  52.     var $num_rows = array();
  53.     var $fetchmode = DB_FETCHMODE_ORDERED; /* Default fetch mode */
  54.  
  55.     // }}}
  56.     // {{{ constructor
  57.  
  58.     /**
  59.      * DB_fbsql constructor.
  60.      *
  61.      * @access public
  62.      */
  63.     function DB_fbsql()
  64.     {
  65.         $this->DB_common();
  66.         $this->phptype = 'fbsql';
  67.         $this->dbsyntax = 'fbsql';
  68.         $this->features = array(
  69.             'prepare' => false,
  70.             'pconnect' => true,
  71.             'transactions' => true,
  72.             'limit' => 'emulate'
  73.         );
  74.         $this->errorcode_map = array(
  75.             1004 => DB_ERROR_CANNOT_CREATE,
  76.             1005 => DB_ERROR_CANNOT_CREATE,
  77.             1006 => DB_ERROR_CANNOT_CREATE,
  78.             1007 => DB_ERROR_ALREADY_EXISTS,
  79.             1008 => DB_ERROR_CANNOT_DROP,
  80.             1046 => DB_ERROR_NODBSELECTED,
  81.             1050 => DB_ERROR_ALREADY_EXISTS,
  82.             1051 => DB_ERROR_NOSUCHTABLE,
  83.             1054 => DB_ERROR_NOSUCHFIELD,
  84.             1062 => DB_ERROR_ALREADY_EXISTS,
  85.             1064 => DB_ERROR_SYNTAX,
  86.             1100 => DB_ERROR_NOT_LOCKED,
  87.             1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
  88.             1146 => DB_ERROR_NOSUCHTABLE,
  89.         );
  90.     }
  91.  
  92.     // }}}
  93.     // {{{ connect()
  94.  
  95.     /**
  96.      * Connect to a database and log in as the specified user.
  97.      *
  98.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  99.      * @param $persistent (optional) whether the connection should
  100.      *        be persistent
  101.      * @access public
  102.      * @return int DB_OK on success, a DB error on failure
  103.      */
  104.     function connect($dsninfo, $persistent = false)
  105.     {
  106.         if (!DB::assertExtension('fbsql')) {
  107.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  108.         }
  109.  
  110.         $this->dsn = $dsninfo;
  111.         $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  112.  
  113.         $php_errormsg = '';
  114.         $connect_function = $persistent ? 'fbsql_pconnect' : 'fbsql_connect';
  115.  
  116.         if ($dbhost && $dsninfo['username'] && $dsninfo['password']) {
  117.             $conn = @$connect_function($dbhost, $dsninfo['username'],
  118.                                        $dsninfo['password']);
  119.         } elseif ($dbhost && $dsninfo['username']) {
  120.             $conn = @$connect_function($dbhost, $dsninfo['username']);
  121.         } elseif ($dbhost) {
  122.             $conn = @$connect_function($dbhost);
  123.         } else {
  124.             $conn = false;
  125.         }
  126.         if (!$conn) {
  127.             if (empty($php_errormsg)) {
  128.                 return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  129.             } else {
  130.                 return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  131.                                          null, $php_errormsg);
  132.             }
  133.         }
  134.  
  135.         if ($dsninfo['database']) {
  136.             if (!fbsql_select_db($dsninfo['database'], $conn)) {
  137.                 return $this->fbsqlRaiseError();
  138.             }
  139.         }
  140.  
  141.         $this->connection = $conn;
  142.         return DB_OK;
  143.     }
  144.  
  145.     // }}}
  146.     // {{{ disconnect()
  147.  
  148.     /**
  149.      * Log out and disconnect from the database.
  150.      *
  151.      * @access public
  152.      *
  153.      * @return bool true on success, false if not connected.
  154.      */
  155.     function disconnect()
  156.     {
  157.         $ret = @fbsql_close($this->connection);
  158.         $this->connection = null;
  159.         return $ret;
  160.     }
  161.  
  162.     // }}}
  163.     // {{{ simpleQuery()
  164.  
  165.     /**
  166.      * Send a query to fbsql and return the results as a fbsql resource
  167.      * identifier.
  168.      *
  169.      * @param the SQL query
  170.      *
  171.      * @access public
  172.      *
  173.      * @return mixed returns a valid fbsql result for successful SELECT
  174.      * queries, DB_OK for other successful queries.  A DB error is
  175.      * returned on failure.
  176.      */
  177.     function simpleQuery($query)
  178.     {
  179.         $this->last_query = $query;
  180.         $query = $this->modifyQuery($query);
  181.         $result = @fbsql_query("$query;", $this->connection);
  182.         if (!$result) {
  183.             return $this->fbsqlRaiseError();
  184.         }
  185.         // Determine which queries that should return data, and which
  186.         // should return an error code only.
  187.         if (DB::isManip($query)) {
  188.             return DB_OK;
  189.         }
  190.         $numrows = $this->numrows($result);
  191.         if (is_object($numrows)) {
  192.             return $numrows;
  193.         }
  194.         $this->num_rows[(int)$result] = $numrows;
  195.         return $result;
  196.     }
  197.  
  198.     // }}}
  199.     // {{{ nextResult()
  200.  
  201.     /**
  202.      * Move the internal fbsql result pointer to the next available result
  203.      *
  204.      * @param a valid fbsql result resource
  205.      *
  206.      * @access public
  207.      *
  208.      * @return true if a result is available otherwise return false
  209.      */
  210.     function nextResult($result)
  211.     {
  212.         return @fbsql_next_result($result);
  213.     }
  214.  
  215.     // }}}
  216.     // {{{ fetchInto()
  217.  
  218.     /**
  219.      * Fetch a row and insert the data into an existing array.
  220.      *
  221.      * Formating of the array and the data therein are configurable.
  222.      * See DB_result::fetchInto() for more information.
  223.      *
  224.      * @param resource $result    query result identifier
  225.      * @param array    $arr       (reference) array where data from the row
  226.      *                            should be placed
  227.      * @param int      $fetchmode how the resulting array should be indexed
  228.      * @param int      $rownum    the row number to fetch
  229.      *
  230.      * @return mixed DB_OK on success, null when end of result set is
  231.      *               reached or on failure
  232.      *
  233.      * @see DB_result::fetchInto()
  234.      * @access private
  235.      */
  236.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  237.     {
  238.         if ($rownum !== null) {
  239.             if (!@fbsql_data_seek($result, $rownum)) {
  240.                 return null;
  241.             }
  242.         }
  243.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  244.             $arr = @fbsql_fetch_array($result, FBSQL_ASSOC);
  245.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  246.                 $arr = array_change_key_case($arr, CASE_LOWER);
  247.             }
  248.         } else {
  249.             $arr = @fbsql_fetch_row($result);
  250.         }
  251.         if (!$arr) {
  252.             $errno = @fbsql_errno($this->connection);
  253.             if (!$errno) {
  254.                 return null;
  255.             }
  256.             return $this->fbsqlRaiseError($errno);
  257.         }
  258.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  259.             $this->_rtrimArrayValues($arr);
  260.         }
  261.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  262.             $this->_convertNullArrayValuesToEmpty($arr);
  263.         }
  264.         return DB_OK;
  265.     }
  266.  
  267.     // }}}
  268.     // {{{ freeResult()
  269.  
  270.     /**
  271.      * Free the internal resources associated with $result.
  272.      *
  273.      * @param $result fbsql result identifier
  274.      *
  275.      * @access public
  276.      *
  277.      * @return bool true on success, false if $result is invalid
  278.      */
  279.     function freeResult($result)
  280.     {
  281.         return @fbsql_free_result($result);
  282.     }
  283.  
  284.     // }}}
  285.     // {{{ autoCommit()
  286.  
  287.     function autoCommit($onoff=false)
  288.     {
  289.         if ($onoff) {
  290.             $this->query("SET COMMIT TRUE");
  291.         } else {
  292.             $this->query("SET COMMIT FALSE");
  293.         }
  294.     }
  295.  
  296.     // }}}
  297.     // {{{ commit()
  298.  
  299.     function commit()
  300.     {
  301.         @fbsql_commit();
  302.     }
  303.  
  304.     // }}}
  305.     // {{{ rollback()
  306.  
  307.     function rollback()
  308.     {
  309.         @fbsql_rollback();
  310.     }
  311.  
  312.     // }}}
  313.     // {{{ numCols()
  314.  
  315.     /**
  316.      * Get the number of columns in a result set.
  317.      *
  318.      * @param $result fbsql result identifier
  319.      *
  320.      * @access public
  321.      *
  322.      * @return int the number of columns per row in $result
  323.      */
  324.     function numCols($result)
  325.     {
  326.         $cols = @fbsql_num_fields($result);
  327.  
  328.         if (!$cols) {
  329.             return $this->fbsqlRaiseError();
  330.         }
  331.  
  332.         return $cols;
  333.     }
  334.  
  335.     // }}}
  336.     // {{{ numRows()
  337.  
  338.     /**
  339.      * Get the number of rows in a result set.
  340.      *
  341.      * @param $result fbsql result identifier
  342.      *
  343.      * @access public
  344.      *
  345.      * @return int the number of rows in $result
  346.      */
  347.     function numRows($result)
  348.     {
  349.         $rows = @fbsql_num_rows($result);
  350.         if ($rows === null) {
  351.             return $this->fbsqlRaiseError();
  352.         }
  353.         return $rows;
  354.     }
  355.  
  356.     // }}}
  357.     // {{{ affectedRows()
  358.  
  359.     /**
  360.      * Gets the number of rows affected by the data manipulation
  361.      * query.  For other queries, this function returns 0.
  362.      *
  363.      * @return number of rows affected by the last query
  364.      */
  365.     function affectedRows()
  366.     {
  367.         if (DB::isManip($this->last_query)) {
  368.             $result = @fbsql_affected_rows($this->connection);
  369.         } else {
  370.             $result = 0;
  371.         }
  372.         return $result;
  373.      }
  374.  
  375.     // }}}
  376.     // {{{ errorNative()
  377.  
  378.     /**
  379.      * Get the native error code of the last error (if any) that
  380.      * occured on the current connection.
  381.      *
  382.      * @access public
  383.      *
  384.      * @return int native fbsql error code
  385.      */
  386.     function errorNative()
  387.     {
  388.         return @fbsql_errno($this->connection);
  389.     }
  390.  
  391.     // }}}
  392.     // {{{ nextId()
  393.  
  394.     /**
  395.      * Returns the next free id in a sequence
  396.      *
  397.      * @param string  $seq_name  name of the sequence
  398.      * @param boolean $ondemand  when true, the seqence is automatically
  399.      *                           created if it does not exist
  400.      *
  401.      * @return int  the next id number in the sequence.  DB_Error if problem.
  402.      *
  403.      * @internal
  404.      * @see DB_common::nextID()
  405.      * @access public
  406.      */
  407.     function nextId($seq_name, $ondemand = true)
  408.     {
  409.         $seqname = $this->getSequenceName($seq_name);
  410.         $repeat = 0;
  411.         do {
  412.             $result = $this->query("INSERT INTO ${seqname} (id) VALUES (NULL)");
  413.             if ($ondemand && DB::isError($result) &&
  414.                 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
  415.                 $repeat = 1;
  416.                 $result = $this->createSequence($seq_name);
  417.                 if (DB::isError($result)) {
  418.                     return $result;
  419.                 }
  420.             } else {
  421.                 $repeat = 0;
  422.             }
  423.         } while ($repeat);
  424.         if (DB::isError($result)) {
  425.             return $result;
  426.         }
  427.         return @fbsql_insert_id($this->connection);
  428.     }
  429.  
  430.     /**
  431.      * Creates a new sequence
  432.      *
  433.      * @param string $seq_name  name of the new sequence
  434.      *
  435.      * @return int  DB_OK on success.  A DB_Error object is returned if
  436.      *              problems arise.
  437.      *
  438.      * @internal
  439.      * @see DB_common::createSequence()
  440.      * @access public
  441.      */
  442.     function createSequence($seq_name)
  443.     {
  444.         $seqname = $this->getSequenceName($seq_name);
  445.         return $this->query("CREATE TABLE ${seqname} ".
  446.                             '(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,'.
  447.                             ' PRIMARY KEY(id))');
  448.     }
  449.  
  450.     // }}}
  451.     // {{{ dropSequence()
  452.  
  453.     /**
  454.      * Deletes a sequence
  455.      *
  456.      * @param string $seq_name  name of the sequence to be deleted
  457.      *
  458.      * @return int  DB_OK on success.  DB_Error if problems.
  459.      *
  460.      * @internal
  461.      * @see DB_common::dropSequence()
  462.      * @access public
  463.      */
  464.     function dropSequence($seq_name)
  465.     {
  466.         $seqname = $this->getSequenceName($seq_name);
  467.         return $this->query("DROP TABLE ${seqname} RESTRICT");
  468.     }
  469.  
  470.     // }}}
  471.     // {{{ modifyQuery()
  472.  
  473.     function modifyQuery($query)
  474.     {
  475.         if ($this->options['portability'] & DB_PORTABILITY_DELETE_COUNT) {
  476.             // "DELETE FROM table" gives 0 affected rows in fbsql.
  477.             // This little hack lets you know how many rows were deleted.
  478.             if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
  479.                 $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  480.                                       'DELETE FROM \1 WHERE 1=1', $query);
  481.             }
  482.         }
  483.         return $query;
  484.     }
  485.  
  486.     // }}}
  487.     // {{{ quoteSmart()
  488.  
  489.     /**
  490.      * Format input so it can be safely used in a query
  491.      *
  492.      * @param mixed $in  data to be quoted
  493.      *
  494.      * @return mixed Submitted variable's type = returned value:
  495.      *               + null = the string <samp>NULL</samp>
  496.      *               + boolean = string <samp>TRUE</samp> or <samp>FALSE</samp>
  497.      *               + integer or double = the unquoted number
  498.      *               + other (including strings and numeric strings) =
  499.      *                 the data escaped according to MySQL's settings
  500.      *                 then encapsulated between single quotes
  501.      *
  502.      * @internal
  503.      */
  504.     function quoteSmart($in)
  505.     {
  506.         if (is_int($in) || is_double($in)) {
  507.             return $in;
  508.         } elseif (is_bool($in)) {
  509.             return $in ? 'TRUE' : 'FALSE';
  510.         } elseif (is_null($in)) {
  511.             return 'NULL';
  512.         } else {
  513.             return "'" . $this->escapeSimple($in) . "'";
  514.         }
  515.     }
  516.  
  517.     // }}}
  518.     // {{{ fbsqlRaiseError()
  519.  
  520.     /**
  521.      * Gather information about an error, then use that info to create a
  522.      * DB error object and finally return that object.
  523.      *
  524.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  525.      *                          manually raising an error
  526.      * @return object  DB error object
  527.      * @see DB_common::errorCode()
  528.      * @see DB_common::raiseError()
  529.      */
  530.     function fbsqlRaiseError($errno = null)
  531.     {
  532.         if ($errno === null) {
  533.             $errno = $this->errorCode(fbsql_errno($this->connection));
  534.         }
  535.         return $this->raiseError($errno, null, null, null,
  536.                         @fbsql_error($this->connection));
  537.     }
  538.  
  539.     // }}}
  540.     // {{{ tableInfo()
  541.  
  542.     /**
  543.      * Returns information about a table or a result set.
  544.      *
  545.      * @param object|string  $result  DB_result object from a query or a
  546.      *                                string containing the name of a table
  547.      * @param int            $mode    a valid tableInfo mode
  548.      * @return array  an associative array with the information requested
  549.      *                or an error object if something is wrong
  550.      * @access public
  551.      * @internal
  552.      * @see DB_common::tableInfo()
  553.      */
  554.     function tableInfo($result, $mode = null) {
  555.         if (isset($result->result)) {
  556.             /*
  557.              * Probably received a result object.
  558.              * Extract the result resource identifier.
  559.              */
  560.             $id = $result->result;
  561.             $got_string = false;
  562.         } elseif (is_string($result)) {
  563.             /*
  564.              * Probably received a table name.
  565.              * Create a result resource identifier.
  566.              */
  567.             $id = @fbsql_list_fields($this->dsn['database'],
  568.                                      $result, $this->connection);
  569.             $got_string = true;
  570.         } else {
  571.             /*
  572.              * Probably received a result resource identifier.
  573.              * Copy it.
  574.              * Deprecated.  Here for compatibility only.
  575.              */
  576.             $id = $result;
  577.             $got_string = false;
  578.         }
  579.  
  580.         if (!is_resource($id)) {
  581.             return $this->fbsqlRaiseError(DB_ERROR_NEED_MORE_DATA);
  582.         }
  583.  
  584.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  585.             $case_func = 'strtolower';
  586.         } else {
  587.             $case_func = 'strval';
  588.         }
  589.  
  590.         $count = @fbsql_num_fields($id);
  591.  
  592.         // made this IF due to performance (one if is faster than $count if's)
  593.         if (!$mode) {
  594.             for ($i=0; $i<$count; $i++) {
  595.                 $res[$i]['table'] = $case_func(@fbsql_field_table($id, $i));
  596.                 $res[$i]['name']  = $case_func(@fbsql_field_name($id, $i));
  597.                 $res[$i]['type']  = @fbsql_field_type($id, $i);
  598.                 $res[$i]['len']   = @fbsql_field_len($id, $i);
  599.                 $res[$i]['flags'] = @fbsql_field_flags($id, $i);
  600.             }
  601.         } else { // full
  602.             $res["num_fields"]= $count;
  603.  
  604.             for ($i=0; $i<$count; $i++) {
  605.                 $res[$i]['table'] = $case_func(@fbsql_field_table($id, $i));
  606.                 $res[$i]['name']  = $case_func(@fbsql_field_name($id, $i));
  607.                 $res[$i]['type']  = @fbsql_field_type($id, $i);
  608.                 $res[$i]['len']   = @fbsql_field_len($id, $i);
  609.                 $res[$i]['flags'] = @fbsql_field_flags($id, $i);
  610.  
  611.                 if ($mode & DB_TABLEINFO_ORDER) {
  612.                     $res['order'][$res[$i]['name']] = $i;
  613.                 }
  614.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  615.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  616.                 }
  617.             }
  618.         }
  619.  
  620.         // free the result only if we were called on a table
  621.         if ($got_string) {
  622.             @fbsql_free_result($id);
  623.         }
  624.         return $res;
  625.     }
  626.  
  627.     // }}}
  628.     // {{{ getSpecialQuery()
  629.  
  630.     /**
  631.      * Returns the query needed to get some backend info
  632.      * @param string $type What kind of info you want to retrieve
  633.      * @return string The SQL query string
  634.      */
  635.     function getSpecialQuery($type)
  636.     {
  637.         switch ($type) {
  638.             case 'tables':
  639.                 return 'select "table_name" from information_schema.tables';
  640.             default:
  641.                 return null;
  642.         }
  643.     }
  644.  
  645.     // }}}
  646. }
  647.  
  648. /*
  649.  * Local variables:
  650.  * tab-width: 4
  651.  * c-basic-offset: 4
  652.  * End:
  653.  */
  654.  
  655. ?>
  656.